/*----------------------------------------------------------------------------*/
/* Copyright 2020-2021 NXP                                                    */
/*                                                                            */
/* NXP Confidential. This software is owned or controlled by NXP and may only */
/* be used strictly in accordance with the applicable license terms.          */
/* By expressly accepting such terms or by downloading, installing,           */
/* activating and/or otherwise using the software, you are agreeing that you  */
/* have read, and that you agree to comply with and are bound by, such        */
/* license terms. If you do not agree to be bound by the applicable license   */
/* terms, then you may not retain, install, activate or otherwise use the     */
/* software.                                                                  */
/*----------------------------------------------------------------------------*/

/** \file
*
* Example Source for NfcrdlibEx10_MIFAREDESFire_EVx that demonstrates communication
* with MIFARE DESFire EV2 contactless IC and MIFARE DESFire EV3 contactless IC cards.
* This example will Detect and activater the Type-A card.
* If card is MIFAREDESFire EV2 and MIFAREDESFire EV3 then it will format the card and create application
* After creating application, it will create one Standard File. It will
* demo read and write operations with the card.
* KEYTYPE is AES.
* Please refer Readme.txt file for Hardware Pin Configuration, Software Configuration and steps to build and
* execute the project which is present in the same project directory.
*
* $Author$
* $Revision$ (v07.02.00)
* $Date$
*
*/

/**
* Reader Library Headers
*/
#include <phApp_Init.h>
#include "BSP.h"
#include "log/log2.h"
#include <Utility.h>

#include <Reader/Reader.h>
#include "Reader/ReaderDesfire2.h"
#include "phpalCt/phpalCt.h"
#include "phalMfdfEVx.h"

#include "Reader/reader_samav3.h"
#include "config/config3.h"


/* *****************************************************************************************************************
* MACROS/Defines
* ***************************************************************************************************************** */
#define PH_EXMFCRYPTO_MFDFCRYPTO_MIFAREDESFIRE_SAK      0x20

#define AES128_KEY_ADDRESS       0       /* PICC Key entry number in key store. */
#define AES128_KEY_VERSION       0       /* PICC Key entry number in key store. */

#define PICC_MASTER_KEY          0
#define APP_MASTER_KEY           0

#define SAM_MASTER_KEY			 0
#define SAM_MASTER_KEY_VERSION	 0

#define KEYCOUNT				 1
#define KEYVERSIONS 			 1

#define PH_EX10_CARD_REMOVED_CHK_CNT  5

#define SAM_LC0         0x00U /**< SAM logical channel 0 */

#define PH_EXCT7816_MAX_ATR_SIZE         33
#define PH_EXCT7816_MAX_NO_APDU          6
#define PH_EXCT7816_APDU_LENGTH          13

#define DESFIRE_DEFAULT 			0x01
#define DESFIRE_DEFAULT_AES			0x02

#define APPLE_KEY_ID_DES			0x21
#define APPLE_KEY_ID_AES			0x22

#define GOOGLE_KEY_ID_AES			0x23

#define SAM_AV3_GET_VERSION_STATE					30
#define SAM_AV3_GET_VERSION_STATE_UNACTIVATED		0x03

#define SAM_KVER_GOOGLE 		0x01
#define SAM_KVER_APPLE_PRIV 	0x01
#define SAM_KVER_APPLE_CRED 	0x01
#define SAM_KVER_LEAF 		0x01


/*******************************************************************************
**   Global Variable Declaration
*******************************************************************************/

phacDiscLoop_Sw_DataParams_t       * pDiscLoop;     /* Pointer to Discovery loop data-params */
phpalI14443p3a_Sw_DataParams_t     * ppalI14443p3a; /* Pointer to PAL 14443-3A data-params */
phpalI14443p4_Sw_DataParams_t      * ppalI14443p4;  /* Pointer to PAL 14443-4 data-params */
phKeyStore_Sw_DataParams_t  	   * pKeyStore;
//phalMfdfEVx_Sw_DataParams_t        * palMfdfEVx;    /* Pointer to MIFAREDESFire Ev2 data-params */
phpalMifare_Sw_DataParams_t			*ppalMifare;


phKeyStore_Sw_KeyEntry_t       keyEntry[KEYCOUNT];
phKeyStore_Sw_KeyVersionPair_t keyVersion[KEYCOUNT * KEYVERSIONS];
phKeyStore_Sw_KUCEntry_t       keyUsage[KEYCOUNT];

extern phhalHw_SamAV3_DataParams_t stHal_SamAv3;
phCryptoSym_Sw_DataParams_t stCryptoEnc;
phCryptoSym_Sw_DataParams_t stCryptoMAC;
phCryptoSym_Sw_DataParams_t stCryptoSymRnd;
phCryptoRng_Sw_DataParams_t stCryptoRng;
phalMfdfEVx_SamAV3_NonX_DataParams_t  palMfdfEVx;	/* Pointer to MIFAREDESFire EVx data-params for SAM in S mode */
phTMIUtils_t						pTMI;


uint8_t aTx_SamBuffer[260];
uint8_t aRx_SamBuffer[260];

uint8_t aTMIBuffer[280];//Buffer for DESFire TMI collection
uint8_t aCmdBuffer[280];//Buffer for DESFire commands

#ifdef PHOSAL_FREERTOS_STATIC_MEM_ALLOCATION
uint32_t MfDesTaskBuffer[MIFAREDESFIRE_TASK_STACK];
#else /* PHOSAL_FREERTOS_STATIC_MEM_ALLOCATION */
#define MfDesTaskBuffer    NULL
#endif /* PHOSAL_FREERTOS_STATIC_MEM_ALLOCATION */



/* AES default key */
static uint8_t aAES128Key[16] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};



/*DESFire default Key entry*/
static uint8_t pDESFireDefault[] = {
		0xD4,0x28,0x31,0xB1,0x16,0x43,0x68,0x44,0xD5,0xAE,0xD5,0x67,0xB1,0xDA,0x14,0xE2,		//KeyValueA
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		0xF5,0x32,0xF0,																					//DF_AID
		0x01,																								//DF_KeyNo
		0x00, 0x00,																							//KeyNo and KeyV CEK
		0xFF,																								//no KUC
		0x24, 0x00,																							//SET
		0x00, 0x00, 0x00,																					//KeyVA,B,C
		0x01, 0x00,																							//EXTSet
		0x00, 0x00																							//KeyNo and KeyV AEK
};
		
/*apple_wallet Key entry*/
static uint8_t apple_wallet_key_des[] = {
		0x30, 0x84, 0x5e, 0xf6, 0x5b, 0x17, 0x25, 0x20, 0xb7, 0x57, 0x36, 0x01, 0x2c, 0x24, 0xd1, 0x16,		//KeyValueA
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		0x00,0x1E,0xA1,																					//DF_AID
		0x00,																								//DF_KeyNo
		0x00, 0x00,																							//KeyNo and KeyV CEK
		0xFF,																								//no KUC
		0x00, 0x00,																							//SET
		0x00, 0x00, 0x00,																					//KeyVA,B,C
		0x01, 0x00,																							//EXTSet
		0x00, 0x00																							//KeyNo and KeyV AEK
};

static uint8_t apple_wallet_key_aes[] = {
		0xab, 0x43, 0x7c, 0xb9, 0xf5, 0x9c, 0xb8, 0x19,	0xf6, 0x70, 0x9d, 0xc1, 0x8f, 0xea, 0xf0, 0xb4,		//KeyValueA
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		0x01,0x1E,0xA1,																					//DF_AID
		0x00,																								//DF_KeyNo
		0x00, 0x00,																							//KeyNo and KeyV CEK
		0xFF,																								//no KUC
		0x24, 0x00,																							//SET
		0x00, 0x00, 0x00,																					//KeyVA,B,C
		0x01, 0x00,																							//EXTSet
		0x00, 0x00																							//KeyNo and KeyV AEK
};

/*===================================================================================*/
#pragma pack(1)
	// typedef struct {
	// 	uint8_t keys[3][16];
	// 	uint8_t aid[3];
	// 	uint8_t key_no;
	// 	uint8_t kce_no,kce_ver;
	// 	uint8_t kuc_no;
	// 	uint16_t set;
	// 	uint8_t key_ver[3];
	// 	uint16_t ext_set;
	// 	uint8_t kae_no,kae_ver;
	// }sam_key_entry_t;

	typedef struct {
		uint8_t tag1;
		uint8_t length1;
		uint8_t tag2;
		uint8_t length2;
		uint8_t info;
		uint8_t pdcap[2];
		uint8_t vcuid[7];
		uint8_t version_id;
		uint8_t timestamp[5];
	}fci_info_t;

	typedef struct {
		uint8_t major;
		uint8_t minor;
		uint8_t customer_code[5];
		uint8_t credential_id[8];
		uint8_t reissue_code;
		uint8_t pin_code[4];
		uint8_t customer_data[20];
		uint8_t signature[8];
	}acd_ev1_t;
	
	typedef struct {	
		uint8_t major;
		uint8_t minor;
		uint8_t customer_code[5];
		uint8_t credential_id[8];
		uint8_t access_data_format;
		uint8_t access_data_bit_length;
		uint8_t access_reader_data[16];
		uint8_t external_printed_number[8];
		uint8_t order_data[5];
		uint8_t reissue_code;
		uint8_t reserved[9];
		uint8_t secure_issuance_digital_signature[8];
		uint8_t reader_digital_signatures[80];
	}acd_t;

	typedef struct {
		uint16_t head;
		uint8_t data[8];
		uint8_t wg_num;
		uint8_t wg_format;
	}default_data_t;
	
	typedef struct {
		uint8_t wg_num;
		uint8_t wg_format;
		uint8_t data[18];
	}custom_data_t;
#pragma pack()
/*===================================================================================*/
/*DESFire default Key entry*/
static sam_key_entry_t google_wallet_key_entry = {
		.keys[0] = {0xD4,0x28,0x31,0xB1,0x16,0x43,0x68,0x44,0xD5,0xAE,0xD5,0x67,0xB1,0xDA,0x14,0xE2},		//KeyValueA
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
//			.aid = {0xF5,0x32,0xF0},																					//DF_AID
//			.key_no = 0x01,																								//DF_KeyNo
		.aid = {0x00,0x00,0x00},																					//DF_AID
		.key_no = 0x00,																								//DF_KeyNo
		.kce_no = 0x00, .kce_ver = 0x00,																							//KeyNo and KeyV CEK
		.kuc_no = 0xFF,																								//no KUC
		.set = 0x00024,																							//SET
		.key_ver = {SAM_KVER_GOOGLE, 0x00, 0x00},																					//KeyVA,B,C
		.ext_set = 0x0001,																							//EXTSet
		.kae_no = 0x00, .kae_ver = 0x00																							//KeyNo and KeyV AEK
};

static sam_key_entry_t apple_wallet_key_entry_des = {
		.keys[0] = {0x30, 0x84, 0x5e, 0xf6, 0x5b, 0x17, 0x25, 0x20, 0xb7, 0x57, 0x36, 0x01, 0x2c, 0x24, 0xd1, 0x16},		//KeyValueA
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
//			.aid = {0x00,0x1E,0xA1},																					//DF_AID
//			.key_no = 0x00,																								//DF_KeyNo
		.aid = {0x00,0x00,0x00},																					//DF_AID
		.key_no = 0x00,																								//DF_KeyNo
		.kce_no = 0x00, .kce_ver = 0x00,																							//KeyNo and KeyV CEK
		.kuc_no = 0xFF,																								//no KUC
		.set = 0x00000,																							//SET
		.key_ver = {SAM_KVER_APPLE_PRIV, 0x00, 0x00},																					//KeyVA,B,C
		.ext_set = 0x0001,																							//EXTSet
		.kae_no = 0x00, .kae_ver = 0x00																							//KeyNo and KeyV AEK
};

static sam_key_entry_t apple_wallet_key_entry_aes = {
		.keys[0] = {0xab, 0x43, 0x7c, 0xb9, 0xf5, 0x9c, 0xb8, 0x19,	0xf6, 0x70, 0x9d, 0xc1, 0x8f, 0xea, 0xf0, 0xb4},		//KeyValueA
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
//			.aid = {0x01,0x1E,0xA1},																					//DF_AID
//			.key_no = 0x00,																								//DF_KeyNo
		.aid = {0x00,0x00,0x00},																					//DF_AID
		.key_no = 0x00,																								//DF_KeyNo
		.kce_no = 0x00, .kce_ver = 0x00,																							//KeyNo and KeyV CEK
		.kuc_no = 0xFF,																								//no KUC
		.set = 0x00024,																							//SET
		.key_ver = {SAM_KVER_APPLE_CRED, 0x00, 0x00},																					//KeyVA,B,C
		.ext_set = 0x0001,																							//EXTSet
		.kae_no = 0x00, .kae_ver = 0x00																							//KeyNo and KeyV AEK
};
/*==============================================================================================================*/
// 默认密钥
static sam_key_entry_t factory_keys[3] = 
{
	//默认读密钥KFR0
	[0] = {
		.keys[0] = {0xD2,0x22,0x9A,0xC0,0xF6,0x9F,0xC8,0x4E,0x87,0x4F,0x2F,0x88,0xD5,0x52,0x5B,0xA6},		//KeyValueA
	//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
	//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		.aid = {0x00,0x00,0x00},																					//DF_AID
		.key_no = 0x00,																								//DF_KeyNo
		.kce_no = 0x00, .kce_ver = 0x00,																							//KeyNo and KeyV CEK
		.kuc_no = 0xFF,																								//no KUC
		.set = 0x0024,																							//SET
		.key_ver = {0x01, 0x02, 0x03},																					//KeyVA,B,C
		.ext_set = 0x0001,																							//EXTSet
		.kae_no = 0x00, .kae_ver = 0x00																							//KeyNo and KeyV AEK
	},
	//读密钥KFR
	[1] = {
		.keys[0] = {0xBF,0x84,0xB0,0xCC,0x39,0xD6,0xE1,0x53,0xE6,0x76,0x06,0xAF,0x46,0x5C,0x66,0x81},		//KeyValueA
	//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
	//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		.aid = {0x00,0x00,0x00},																					//DF_AID
		.key_no = 0x00,																								//DF_KeyNo
		.kce_no = 0x00, .kce_ver = 0x00,																							//KeyNo and KeyV CEK
		.kuc_no = 0xFF,																								//no KUC
		.set = 0x0024,																							//SET
		.key_ver = {0x01, 0x02, 0x03},																					//KeyVA,B,C
		.ext_set = 0x0001,																							//EXTSet OfflineCrypto
		.kae_no = 0x00, .kae_ver = 0x00																							//KeyNo and KeyV AEK
	},
	//MAC密钥KFM
	[2] = {
	 	.keys[0] = {0x35,0x55,0x98,0x72,0x35,0xAA,0x4D,0xFB,0xF4,0xD8,0x35,0xC0,0x45,0xDF,0xDB,0x98},		//KeyValueA
//			.keys[0] = {0x7A,0x6B,0x47,0x73,0xE8,0x6C,0x1F,0x5A,0xB1,0x8D,0x06,0xE7,0xAC,0xF1,0x89,0x2D},		//KeyValueA
//			.keys[0] = {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},		//KeyValueA

		//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
	//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		.aid = {0x00,0x00,0x00},																					//DF_AID
		.key_no = 0x00,																								//DF_KeyNo
		.kce_no = 0x00, .kce_ver = 0x00,																							//KeyNo and KeyV CEK
		.kuc_no = 0xFF,																								//no KUC
		.set = 0x0020,																							//SET
		.key_ver = {0x01, 0x02, 0x03},																					//KeyVA,B,C
		.ext_set = 0x0004,																							//EXTSet OfflineCrypto 
		.kae_no = 0x00, .kae_ver = 0x00																							//KeyNo and KeyV AEK
	},	
};

/*==============================================================================================================*/
/* *****************************************************************************************************************
* Types/Structure Declarations
* ***************************************************************************************************************** */

/* *****************************************************************************************************************
* Function Prototypes
* ***************************************************************************************************************** */


/*******************************************************************************
**   Function Definitions
*******************************************************************************/

int reader_wavelynx_init(void){
    phStatus_t  status = 0;
    uint16_t    wTechDetected = 0;
    uint8_t     bTagType;
    uint8_t     bCardRemoved = 0U;

    /** Instance for  CT pal parameter's structure */
	phpalCt_DataParams_t pDataParams ;

	/* Initialize library */
	
	/* Set the generic pointer */
	ppalI14443p3a = (phpalI14443p3a_Sw_DataParams_t *) phNfcLib_GetDataParams(PH_COMP_PAL_ISO14443P3A);
	ppalI14443p4 = (phpalI14443p4_Sw_DataParams_t *) phNfcLib_GetDataParams(PH_COMP_PAL_ISO14443P4);
	ppalMifare= (phpalMifare_Sw_DataParams_t *) phNfcLib_GetDataParams(PH_COMP_PAL_MIFARE);
	
	phTMIUtils_Init(&pTMI,aTMIBuffer,sizeof(aTMIBuffer));
	
	//INIT DESFire Params
	status = phalMfdfEVx_SamAV3_NonX_Init(
				&palMfdfEVx,
				sizeof(palMfdfEVx),
				&stHal_SamAv3,
				ppalMifare,
				&pTMI,
				aCmdBuffer,
				sizeof(aCmdBuffer)
			 );
	
	if(status != PH_ERR_SUCCESS) {
		DEBUG_PRINTF("\n DESFire Init failed!");
		DEBUG_ERROR_PRINT(status);
	}

	return status;
}



static uint8_t google_wallet_key[16] = {
	0xD4,0x28,0x31,0xB1,0x16,0x43,0x68,0x44,0xD5,0xAE,0xD5,0x67,0xB1,0xDA,0x14,0xE2
};

static uint8_t apple_wallet_key_priv[16] = {
	0x30, 0x84, 0x5e, 0xf6, 0x5b, 0x17, 0x25, 0x20, 0xb7, 0x57, 0x36, 0x01, 0x2c, 0x24, 0xd1, 0x16
};

static uint8_t apple_wallet_key_cred[16] = {
	0xab, 0x43, 0x7c, 0xb9, 0xf5, 0x9c, 0xb8, 0x19,	0xf6, 0x70, 0x9d, 0xc1, 0x8f, 0xea, 0xf0, 0xb4
};

static uint8_t leaf_key[16] = {
	0xDB,0x01,0x01,0x01,
	0x01,0x01,0x01,0x01,
	0x01,0x01,0x01,0x01,
	0x01,0x01,0x01,0x01
};

int reader_wavelynx_load_default_keys(void){
	int ret;
	//装载Google AES密钥
	LOG2_PRINT("\nGoogle AES key loading: ");
	ret = samav3_load_key_if_changed(SAM_KID_GOOGLE, google_wallet_key, SAM_KVER_GOOGLE, SAM_KEY_CLASS_PICC, SAM_KEY_T_AES_128, 1);
	if(ret < 0) {
		LOG2_PRINT("Failed to load Google AES key: %d\n", ret);
	}
	else {
		LOG2_PRINT("Load Google AES key successful!");
	}
	//装载Google MAC密钥
	ret = samav3_load_key_if_changed(SAM_KID_GOOGLE_MAC, google_wallet_key, SAM_KVER_GOOGLE, SAM_KEY_CLASS_OfflineCrypto, SAM_KEY_T_AES_128, 0);
	if(ret < 0) {
		LOG2_PRINT("Failed to load Google MAC key: %d\n", ret);
	}
	else {
		LOG2_PRINT("Load Google MAC key successful!");
	}
	//装载Apple DES密钥
	LOG2_PRINT("\nApple DES key loading: ");
	ret = samav3_load_key_if_changed(SAM_KID_APPLE_PRIV, apple_wallet_key_priv, SAM_KVER_APPLE_PRIV, SAM_KEY_CLASS_PICC, SAM_KEY_T_DESFire4, 0);
	if(ret < 0) {
		LOG2_PRINT("Failed to load Apple DES key: %d\n", ret);
	}
	else {
		LOG2_PRINT("Load Apple DES key successful!");
	}
	//装载Apple AES密钥
	LOG2_PRINT("\nApple AES key loading: ");
	ret = samav3_load_key_if_changed(SAM_KID_APPLE_CRED, apple_wallet_key_cred, SAM_KVER_APPLE_CRED, SAM_KEY_CLASS_PICC, SAM_KEY_T_AES_128, 1);
	if(ret < 0) {
		LOG2_PRINT("Failed to load Apple AES key: %d\n", ret);
	}
	else {
		LOG2_PRINT("Load Apple AES key successful!");
	}
	//装载Leaf密钥
	LOG2_PRINT("\nLeaf key loading: ");
	ret = samav3_load_key_if_changed(SAM_KID_LEAF, leaf_key, SAM_KVER_LEAF, SAM_KEY_CLASS_PICC, SAM_KEY_T_AES_128, 1);
	if(ret < 0) {
		LOG2_PRINT("Failed to load Leaf key: %d\n", ret);
	}
	else {
		LOG2_PRINT("Load Leaf key successful!");
	}
	ret = samav3_load_key_if_changed(SAM_KID_LEAF_MAC, leaf_key, SAM_KVER_LEAF, SAM_KEY_CLASS_OfflineCrypto, SAM_KEY_T_AES_128, 0);
	if(ret < 0) {
		LOG2_PRINT("Failed to load Leaf MAC key: %d\n", ret);
	}
	else {
		LOG2_PRINT("Load Leaf MAC key successful!");
	}
	return ret;
}

/*===================================================================================*/
//检测密钥是否有效
static int reader_check_keys(const key_t *keys, uint8_t num_keys){
	int ret = 0;
	for(int i = 0; i < num_keys; i++){
		if(keys[i].id == 0 || keys[i].type == KEY_T_NONE){
			ret = -1;
			break;
		}
	}
	return ret;
}


static void reader_get_access_data(uint8_t *customer_data, credential_t* cred){
	default_data_t* def_data = (default_data_t*)customer_data;
	if(def_data->head == 0x1001){
		//默认格式
		uint8_t len = def_data->wg_num / 8;
		if(def_data->wg_num & 0x07){
			len++;
		}
		cred->nbit = def_data->wg_num;
		cred->clen = len;
		Mem_Backward_Copy(cred->credential, len, def_data->data, sizeof(def_data->data), len);
	}
	else{
		//自定义格式
		custom_data_t* custom = (custom_data_t*)customer_data;
		uint8_t len = custom->wg_num / 8;
		if(custom->wg_num & 0x07){
			len++;
		}
		cred->nbit = custom->wg_num;
		cred->clen = len;
		Mem_Backward_Copy(cred->credential, len, custom->data, sizeof(custom->data), len);
	}
	cred->tag.type = HFTAG_WAVELYNX;
}

static void reader_print_fci(const fci_info_t* fci){
	LOG2_PRINT("\n===========FCI============\n");
	LOG2_PRINT("info: %02X\n", fci->info);
	LOG2_PRINT("pdcap: %02X%02X\n", fci->pdcap[0], fci->pdcap[1]);
	LOG2_PRINT("vcuid: %02X%02X%02X%02X%02X%02X%02X\n", fci->vcuid[0], fci->vcuid[1], 
		fci->vcuid[2], fci->vcuid[3], fci->vcuid[4], fci->vcuid[5], fci->vcuid[6]);
	LOG2_PRINT("version_id: %02X\n", fci->version_id);
	LOG2_PRINT("timestamp: %02X%02X%02X%02X%02X\n", fci->timestamp[0], fci->timestamp[1], 
		fci->timestamp[2], fci->timestamp[3], fci->timestamp[4]);
	LOG2_PRINT("===========================\n");
}

static uint8_t reader_mf2go_gen_div(const fci_info_t* fci, const uint8_t aid[3], uint8_t *div){
	uint8_t len = 0;
//		div[len++] = 0x01;
	memcpy(&div[len], fci->vcuid, sizeof(fci->vcuid));
	len += sizeof(fci->vcuid);
	memcpy(&div[len], aid, 3);
	len += 3;
	div[len++] = fci->info;
	memcpy(&div[len], fci->timestamp, sizeof(fci->timestamp));
	len += sizeof(fci->timestamp);
	return len;
}

static uint32_t reader_read_google_wallet(param_google_wallet_t* param, key_t* key, credential_t* cred){
	int ret;
	phStatus_t status;
	void* pDataParams  = phNfcLib_GetDataParams(PH_COMP_AL_MFDFEVX);
	uint8_t keyNo =1;
	uint8_t ver = 0;
	void* key_store = phNfcLib_GetDataParams(PH_COMP_KEYSTORE);
	if(reader_check_keys(key, 1)){
		return 2;
	}
	//1. Activate and identify credential using ISO SELECT.
	fci_info_t fci_info = {0};
{
	uint8_t *pFCI = NULL;
	uint16_t wFCILen = 0;
	status = phalMfdfEVx_IsoSelectFile(pDataParams, 0x00U, PHAL_MFDFEVX_SELECTOR_4, NULL, 
		(uint8_t*)param->df_name, sizeof(param->df_name), 0, &pFCI, &wFCILen);
	if(status){
		LOG2_ERR("phalMfdfEVx_IsoSelectFile fail: %04X", status);
		return 1;
	}
	LOG2_BUF_DBG("FCI", pFCI, wFCILen);
	
	uint8_t len = wFCILen < sizeof(fci_info) ? wFCILen : sizeof(fci_info);
	memcpy(&fci_info, pFCI, len);
	reader_print_fci(&fci_info);
}
	key_set_t *key_set = &param->key_set;
//		2. DESFire application 0xF532F0 is auto selected as primary application.
//		3. Read/Write encryption key for application is diversified using FCI data.
	uint8_t div[32] = {0};
	uint8_t dlen = reader_mf2go_gen_div(&fci_info, key_set->aid, div);
	
	LOG2_BUF_DBG("div", div, dlen);

//		4. DESFire application is authenticated using key 1.
{
		// key_t* key = &config_key.google_key;
		keyNo = 1;
		uint16_t key_type = PH_KEYSTORE_KEY_TYPE_AES128;
	 	LOG2_DBG("keyNo: %d, ver: %d, key_no: %d", keyNo, ver, key_set->key_no);
		LOG2_BUF_DBG("key", key->data, sizeof(key->data));
		phKeyStore_FormatKeyEntry(key_store, keyNo, PH_KEYSTORE_KEY_TYPE_AES128);
		phKeyStore_SetKeyAtPos(key_store, keyNo, 0, key_type, key->data, ver);
		ret = Reader_MFDF_AuthenticateAES(PHAL_MFDFEVX_DIV_METHOD_CMAC, keyNo, ver, key_set->key_no, div, dlen);
		if(ret){
			LOG2_ERR("Reader_MFDF_Authenticate fail: %04X", ret);
			return 2;
		}
}

//		5. Credential data is read from file 2 of application.
//	acd_ev1_t acd = {0};
	uint8_t bFileNo = param->file_no;

{
	uint8_t *data = NULL;
	uint16_t dlen = 0;
	uint8_t offset[3] = {0x00, 0x00, 0x00};
	uint8_t length[3] = {sizeof(acd_ev1_t), 0x00, 0x00};
	LOG2_DBG("read data");
	ret = Reader_MFDF_ReadData(PHAL_MFDFEVX_COMMUNICATION_ENC, PHAL_MFDFEVX_APPLICATION_CHAINING, bFileNo, offset, length, &data, &dlen);
	if(ret){
		LOG2_ERR("Reader_MFDF_ReadData fail: %04X", ret);
		return 3;
	}
	LOG2_BUF_DBG("data", data, dlen);
	if(dlen != sizeof(acd_ev1_t)){
		LOG2_ERR("dlen=%d, len=%d", dlen, sizeof(acd_ev1_t));
		return 4;
	}
//		SimpleTag_T tag;
	acd_ev1_t* acd = (acd_ev1_t*)data;
	reader_get_access_data(acd->customer_data, cred);
	LOG2_DBG("wg: %d", cred->nbit);
	LOG2_BUF_DBG("data", cred->credential, cred->clen);
}
	
//		6. A WRITE command is performed on the Reissue Code field.
{
	uint8_t data[1] = { 0 };
	uint16_t dlen = 0;
	uint8_t offset[3] = {0x0F, 0x00, 0x00};
	uint8_t length[3] = {1, 0x00, 0x00};
	LOG2_DBG("write data");
	ret = Reader_MFDF_WriteData(PHAL_MFDFEVX_COMMUNICATION_ENC, PHAL_MFDFEVX_APPLICATION_CHAINING, bFileNo, offset, data, length);
	if(ret){
		LOG2_ERR("Reader_MFDF_ReadData fail: %04X", ret);
		return 5;
	}
}

//		7. A COMMIT TRANSACTION command is performed to end exchange.

	uint8_t end_apdu[] = {0x90, 0xC7, 0x00, 0x00, 0x00};
	uint8_t *end_rapdu;
	uint16_t end_rlen;
	LOG2_DBG("COMMIT TRANSACTION");
	phpalI14443p4_Sw_DataParams_t*	ppalI14443p4 = (phpalI14443p4_Sw_DataParams_t *) phNfcLib_GetDataParams(PH_COMP_PAL_ISO14443P4);

	phpalI14443p4_Exchange(ppalI14443p4, PH_EXCHANGE_DEFAULT, end_apdu, sizeof(end_apdu), &end_rapdu, &end_rlen);

//7. DESELECT credential.
	phpalI14443p4_Deselect(ppalI14443p4);

	return 0;
}


//获取分散因子
static int reader_read_aw_div(param_apple_wallet_t* param, key_t* key, uint8_t* div, uint8_t* dlen){
		int ret;
	//2. SELECT the Privacy application and authenticate using the undiversified key.
		key_set_t* key_set = &param->key_sets[0];
		
		ret = Reader_MFDF_SelectApplication(PHAL_MFDFEVX_SELECT_PRIMARY_APP, key_set->aid, NULL);
		if(ret){
			uint32_t aid = 0;
			memcpy(&aid, key_set->aid, 3);
			LOG2_ERR("select app(%06X) fail: %04X", aid, ret);
			return 1;
		}
	//3. Read the static UID/CSN of the credential following Privacy app authentication.
		uint8_t keyNo = 1;		
		uint8_t ver = 0;
		void* key_store = phNfcLib_GetDataParams(PH_COMP_KEYSTORE);
		// key_t* key = &config_key.apple_keys[0];
		uint8_t *key_des = key->data;
		uint8_t key_type = PH_KEYSTORE_KEY_TYPE_2K3DES;
		phKeyStore_FormatKeyEntry(key_store, keyNo, key_type);
		phKeyStore_SetKeyAtPos(key_store, keyNo, 0, key_type, key_des, ver);
		ret = Reader_MFDF_Authenticate(PHAL_MFDFEVX_NO_DIVERSIFICATION, keyNo, ver, key_set->key_no, NULL, 0);
		if(ret){
			LOG2_ERR("auth fail: %04X", ret);
			return 2;
		}
		uint8_t uid[8];
		ret = Reader_MFDF_GetCardUID(PHAL_MFDFEVX_GET_CARD_UID_EXCHANGE_OPTION_OFF, 
			PHAL_MFDFEVX_GET_CARD_UID_OPTION_NUID_NOT_RETURNED, uid);
		if(ret){
			LOG2_ERR("Reader_MFDF_GetCardUID fail: %04X", ret);
			return 3;
		}
		LOG2_BUF_DBG("uid:", uid, 7);
		memcpy(div, uid, 7);
		*dlen = 7;
		return 0;
}

static int reader_read_aw_data(param_apple_wallet_t* param, key_t* key, uint8_t* div, uint8_t div_len, uint8_t* rdata, uint8_t* rlen){
	int ret;
	key_set_t* key_set = &param->key_sets[1];
	void* key_store = phNfcLib_GetDataParams(PH_COMP_KEYSTORE);
//4. Diversify Credential application key using static UID from step 2.
//5. SELECT and authenticate Credential application using diversified key.
	LOG2_BUF_DBG("aid", key_set->aid, 3);
	ret = Reader_MFDF_SelectApplication(PHAL_MFDFEVX_SELECT_PRIMARY_APP, key_set->aid, NULL);
	if(ret){
		uint32_t aid = 0;
		memcpy(&aid, key_set->aid, 3);
		LOG2_ERR("Reader_MFDF_SelectApplication(%06X) fail: %04X", aid, ret);
		return 4;
	}
	uint8_t ver = 0;
	uint8_t keyNo = 1;	
	uint8_t* key_aes = key->data;
	uint8_t key_type = PH_KEYSTORE_KEY_TYPE_AES128;
	LOG2_DBG("keyNo: %d, ver: %d, key_no: %d", keyNo, ver, key_set->key_no);
	LOG2_BUF_DBG("key", key_aes, 16);
	LOG2_BUF_DBG("div", div, div_len);
	phKeyStore_FormatKeyEntry(key_store, keyNo, key_type);
	phKeyStore_SetKeyAtPos(key_store, keyNo, 0,	key_type, key_aes, ver);
	ret = Reader_MFDF_AuthenticateAES(PHAL_MFDFEVX_DIV_METHOD_CMAC, keyNo, ver, key_set->key_no, div, div_len);
	if(ret){
		LOG2_ERR("Reader_MFDF_Authenticate fail: %04X", ret);
		return 5;
	}
//6. READ first 40 bits of data from Credential application.
	uint8_t bFileNo = param->file_no;
	uint8_t olen = param->length > 32 ? 32 : param->length;
	uint8_t flen = (param->format + 7) / 8;
	if(olen < flen){
		olen = flen;
	}
	uint8_t *data = NULL;
	uint16_t dlen = 0;
	uint8_t offset[3] = {0x00, 0x00, 0x00};
	uint8_t length[3] = {olen, 0x00, 0x00};
	ret = Reader_MFDF_ReadData(PHAL_MFDFEVX_COMMUNICATION_ENC, 0, bFileNo, offset, length, &data, &dlen);
	if(ret){
		LOG2_ERR("Reader_MFDF_ReadData fail: %04X", ret);
		return 6;
	}
	LOG2_BUF_DBG("data:", data, olen);

	memcpy(rdata, data, olen);
	*rlen = olen;
	
	uint8_t end_apdu[] = {0x90, 0xee, 0x00, 0x00, 0x00};
	uint8_t *end_rapdu;
	uint16_t end_rlen;
	phpalI14443p4_Sw_DataParams_t*	ppalI14443p4 = (phpalI14443p4_Sw_DataParams_t *) phNfcLib_GetDataParams(PH_COMP_PAL_ISO14443P4);

	phpalI14443p4_Exchange(ppalI14443p4, PH_EXCHANGE_DEFAULT, end_apdu, sizeof(end_apdu), &end_rapdu, &end_rlen);
//7. DESELECT credential.
	phpalI14443p4_Deselect(ppalI14443p4);

	return 0;
}

static uint32_t reader_read_apple_wallet(param_apple_wallet_t* param, key_t key[2], credential_t* cred){
	int ret;
	uint8_t div[8];
	uint8_t div_len = 0;
	if(reader_check_keys(key, 2)){
		return 2;
	}
	//获取分散因子
	ret = reader_read_aw_div(param, &key[0], div, &div_len);

	if(ret){
		return ret;
	}
	uint8_t rdata[32];
	uint8_t rlen = 0;
	//读数据
	ret = reader_read_aw_data(param, &key[1], div, div_len, rdata, &rlen);

	if(ret){
		return ret;
	}
	uint8_t size = (param->format+7)/8;
	memcpy(cred->credential, rdata, size);
	cred->clen = size;
	cred->nbit = size * 8;
	cred->tag.type = HFTAG_WAVELYNX;
	return 0;
}
/*读Leaf卡*/
static int reader_read_leaf(param_leaf_t* param, key_t* key, credential_t* cred){
	phStatus_t status;
	void* key_store = phNfcLib_GetDataParams(PH_COMP_KEYSTORE);
	uint8_t *uid = cred->tag.uid;
	uint8_t ulen = cred->tag.ulen; 
	// uint32_t aid = 0xF51CDB;
	if(reader_check_keys(key, 1)){
		return 2;
	}
	key_set_t* key_set = &param->key_set;
	uint32_t aid = 0;
	memcpy(&aid, key_set->aid, 3);

	/* SelectApplication */
	LOG2_PRINT("\nDESFire Select application(%06X).", aid);	
	status = Reader_MFDF_SelectApplication(PHAL_MFDFEVX_SELECT_PRIMARY_APP, key_set->aid, NULL);
	if(status){
		LOG2_ERR("phalMfdfEVx_SelectApplication fail: %04X", status);
		return 1;
	}
	
	uint8_t ver = 0;
	uint8_t keyNo = 1;
	// key_t* key = &config_key.apple_keys[1];
	uint8_t* key_aes = key->data;
	uint8_t key_type = PH_KEYSTORE_KEY_TYPE_AES128;
	phKeyStore_FormatKeyEntry(key_store, keyNo, key_type);
	phKeyStore_SetKeyAtPos(key_store, keyNo, 0,	key_type, key_aes, ver);

	uint8_t div[32] = {0};
	uint8_t dlen = 0;
	memcpy(div, uid, ulen);
	dlen = ulen;
	LOG2_BUF_DBG("div", div, dlen);
	uint8_t key_no_card = key_set->key_no;
	LOG2_INF("\nphalMfdfEVx_AuthenticateAES: \n");
	/*AES Authenticate First*/
	status = Reader_MFDF_AuthenticateAES(PHAL_MFDFEVX_DIV_METHOD_CMAC, keyNo, ver, key_no_card, div, dlen);
	CHECK_SUCCESS(status);
	 
	uint8_t bFileNo = param->file_no;
	uint8_t Len[] = {sizeof(acd_t),0x00,0x00}; //LSB first!
	uint8_t Offset[] = {0x00,0x00,0x00};//LSB first!

	uint16_t RxLen = 0;

	uint8_t RxData[sizeof(acd_t)+16];
	uint8_t * pRxData = NULL;
	uint8_t rlen = 0;
	memset(RxData, 0, sizeof(RxData));
	LOG2_INF("\nDESfire read data: \n");
	status = Reader_MFDF_ReadData(PHAL_MFDFEVX_COMMUNICATION_ENC, PHAL_MFDFEVX_APPLICATION_CHAINING, 
			bFileNo, Offset, Len, &pRxData, &RxLen);

	while((status & PH_ERR_MASK) == PH_ERR_SUCCESS_CHAINING){
		if ((rlen + RxLen) > sizeof(RxData)) {
			LOG2_ERR("Buffer overflow detected");
			return PH_ERR_BUFFER_OVERFLOW;
		}
		LOG2_PRINT("chaining\n");
		memcpy(RxData+rlen, pRxData, RxLen);
		rlen += RxLen;
		pRxData = NULL;
		RxLen = 0;
		status = Reader_MFDF_ReadData(
					PHAL_MFDFEVX_COMMUNICATION_ENC|PH_EXCHANGE_RXCHAINING, 
					PHAL_MFDFEVX_APPLICATION_CHAINING, 
					bFileNo, Offset, Len, &pRxData, &RxLen
				);
	}
	CHECK_SUCCESS(status);
	if ((rlen + RxLen) > sizeof(RxData)) {
		LOG2_ERR("Buffer overflow detected");
		return PH_ERR_BUFFER_OVERFLOW;
	}
	memcpy(RxData+rlen, pRxData, RxLen);
	rlen += RxLen;
	acd_t* acd = (acd_t*)RxData;
	LOG2_INF("access format:%d, access bit length: %d", acd->access_data_format, acd->access_data_bit_length);
	LOG2_BUF_INF("access reader data", acd->access_reader_data, 16);
	
	uint8_t len = (acd->access_data_bit_length + 7) / 8;
	cred->nbit = acd->access_data_bit_length;
	cred->clen = len;
	Mem_Backward_Copy(cred->credential, len, acd->access_reader_data, sizeof(acd->access_reader_data), len);
	cred->tag.type = HFTAG_WAVELYNX;
	LOG2_BUF_INF("credential", cred->credential, cred->clen);

	return status;
}

int reader_read_wavelynx_tag(Reader_T* read, credential_t* cred){
	int ret = reader_read_apple_wallet(&config_param.apple_wallet, config_key.apple_keys, cred);
	if(ret){
		if(cred->tag.ulen == 4){
			ret = reader_read_google_wallet(&config_param.google_wallet, &config_key.google_key, cred);
		}
		else{
			ret = reader_read_leaf(&config_param.leaf, &config_key.leaf_key, cred);
		}
	}
#if 0
	uint32_t aid = 0;
	Reader_MFDF_SelectApplication(PHAL_MFDFEVX_SELECT_PRIMARY_APP, (uint8_t*)&aid, NULL);
#endif 
	return ret;
}


/***********************************************************************************************
*                            End Of File
**********************************************************************************************/

